import { CanvasTexture, ClampToEdgeWrapping, LinearFilter, Sprite, SpriteMaterial, Vector2 } from "three";
import { App } from "../../application";
import Const from "../../application/constants/Const";

/**
 * 二维POI图标（非DOM对象）
 */
export default class Poi extends Sprite {
  /**
   * 标注名称
   */
  public name;// = '标注标注标注标注标注';

   /**
   * 背景色
   */
   public backGroundStyle;// = 'black';

  /**
   * 字体颜色
   */
  public textStyle = 'white';
  private strokeStyle = 'black';
  private strokeWidth = 5;
  /**
   * 字号
   */
  public size = 32;
  /**
   * 是否加粗
   */
  public isBold = false;
  /**
   * 是否是斜体
   */
  public isItalic = false;
  /**
   * 字体
   */
  public textfont = 'sans-serif';
  /**
   * 文字对齐方式
   */
  public textAlign: CanvasTextAlign = 'center';
  /**
   * 文字对齐位置
   */
  public textBaseline: CanvasTextBaseline = 'middle';
  /**
   * 是否显示文字
   */
  public showText = true;
  /**
   * 图片对象
   */
  public image;

  /**
   * 图片URL
   */
  public url;
  /**
   * 图片大小
   */
  public baseImageSize = 100;
  private depthTest: boolean;
  public app: App;

  /**
   * 构造函数
   * @param cfg 
   * @param cfg.url 模型图片路径
   * @param cfg.position POI位置
   * @param cfg.name POI显示的文字
   * @param cfg.size 文字大小
   * @param cfg.isBold 文字是否加粗
   * @param cfg.baseImageSize 图片大小（长宽一致，默认1000）
   * @param cfg.showText 是否显示文字
   * @param cfg.textStyle 字体颜色
   * @param cfg.strokeStyle 字体描边颜色
   * @param cfg.strokeWidth 字体描边宽度
   * @param cfg.textfont 字体格式 字体的支持情况跟操作系统和浏览器环境有关，sans-serif是默认字体都支持，其余字体不保证正常显示
   * @param cfg.center POI的锚点,用于控制POI位置的偏移，默认是[0.5, 0.5]居中，如果是[0, 0]则在左下角显示，[1, 1]则在右上角显示
   * @param cfg.depthTest 是否开启深度检测，可选参数，默认开启
   * @example  let poi = new GE.Poi({
       url: '/examples/resources/images/tower.png', //模型图片路径
       position: new GE.Point(120.170646, 30.28362, 10), //POI位置，不传就是0,0,0原点
       name: 'POI的名字', //显示的文字名称
       size: 200, //文字大小
       isBold: true, //是否加粗
       baseImageSize: 1000, //图片大小（长宽一致，都是这个值）最大1500
       showText: true,//是否显示文字
       textStyle: '#ffffff',//字体颜色
       textfont: 'sans-serif'//字体格式 字体的支持情况跟操作系统和浏览器环境有关，sans-serif是默认字体都支持，其余字体不保证正常显示
   })
   app.add(poi);
   */
  constructor(cfg) {
    super(null);
    this.app = App.getInstance();
    this.name = (cfg.name === undefined) ? this.name : cfg.name;
    this.backGroundStyle = cfg.backGroundStyle ? cfg.backGroundStyle : this.backGroundStyle;
    this.textStyle = cfg.textStyle ? cfg.textStyle : this.textStyle;
    this.strokeStyle = cfg.strokeStyle ? cfg.strokeStyle : this.strokeStyle;
    this.strokeWidth = cfg.strokeWidth ? cfg.strokeWidth : this.strokeWidth;
    this.size = cfg.size ? cfg.size : this.size;
    this.isBold = (cfg.isBold === undefined) ? this.isBold : cfg.isBold;
    this.isItalic = (cfg.isItalic === undefined) ? this.isItalic : cfg.isItalic;
    this.textfont = cfg.textfont ? cfg.textfont : this.textfont;
    this.textAlign = cfg.textAlign ? cfg.textAlign : this.textAlign;
    this.textBaseline = cfg.textBaseline ? cfg.textBaseline : this.textBaseline;
    this.baseImageSize = Math.min(1500, cfg.baseImageSize ? cfg.baseImageSize : this.baseImageSize);
    this.showText = (cfg.showText === undefined) ? this.showText : cfg.showText;
    this.center = cfg.center ? new Vector2(cfg.center[0], cfg.center[1]) : this.center;
    this.url = cfg.url;
    if (cfg.position) {
      cfg.position = cfg.position.toEPSGWeb();
      this.position.set(cfg.position.x, cfg.position.y, cfg.position.z);
    }
    this.depthTest =(cfg.depthTest == undefined) ? true : cfg.depthTest;

    this.image = new Image();
    let scope = this;
    let image = new Image();
    image.src = this.url;
    image.setAttribute('crossOrigin', 'anonymous');
    image.onload = function () {
      scope.image = image;
      scope.make();
    }

    this.renderOrder = Infinity;
    this.make();
  }

  private makeCanvas(image) {
    const borderSize = 5;

    //设置文字的字体大小
    const ctx = document.createElement('canvas').getContext('2d');
    let font = `${this.isBold ? 'bold ' : ''}${this.isItalic ? ' italic' : ''}${this.size}px ${this.textfont}`;
    ctx.font = font;

    if (this.name) {
      //计算文字长度
      const textWidth = ctx.measureText(this.name).width;

      //计算canvas的宽高
      const doubleBorderSize = borderSize * 2;
      //宽度取文字背景板和图片大小中最大的那个
      const width = Math.max(textWidth + doubleBorderSize, this.baseImageSize);
      //高度为文字背景板加图片大小
      const height = this.size + doubleBorderSize + this.baseImageSize;
      ctx.canvas.width = width;
      ctx.canvas.height = height;

      //重设canvas大小后需要对font重新赋值
      ctx.font = font;
      //设置文字的对其方式
      ctx.textBaseline = this.textBaseline;
      ctx.textAlign = this.textAlign;

      if(this.showText && this.backGroundStyle){
        //先绘制文字的背景板
        ctx.fillStyle = this.backGroundStyle;
        ctx.fillRect(0, 0, width, this.size + doubleBorderSize);
      }

      ctx.translate(width / 2, (this.size + doubleBorderSize) / 2 + doubleBorderSize);

      if (this.showText) {
        ctx.shadowColor = this.strokeStyle;
        ctx.shadowBlur = this.strokeWidth; // 增加模糊效果
        ctx.shadowOffsetX = this.strokeWidth; // 阴影偏移量
        ctx.shadowOffsetY = this.strokeWidth; // 阴影偏移量
        
        // ctx.lineWidth = this.strokeWidth; // 设置线条宽度, 用于描边
        
        ctx.fillStyle = this.textStyle;

        ctx.strokeStyle = this.strokeStyle;

        //用strokeText给背景板描边，用fillText填充文字
        ctx.strokeText(this.name, borderSize, borderSize);
        ctx.fillText(this.name, borderSize, borderSize);
      }

      //移动至图片所在位置，绘制图片
      //由于canvas绘制图片只能从左上角开始，所以我们要移动到的位置的高度是文字背景板的最下方，宽度位置是中间偏左，偏移距离是图片大小的一半
      ctx.translate(-this.baseImageSize / 2, (this.size + doubleBorderSize) / 2);
    } else {
      ctx.canvas.width = this.baseImageSize;
      ctx.canvas.height = this.baseImageSize;
    }

    //ctx.scale(1, height / width);
    ctx.drawImage(image, 0, 0, this.baseImageSize, this.baseImageSize);

    return ctx.canvas;
  }

  /**
   * 重新生成POI图表，修改属性后必须执行这个函数才生效
   */
  public async make() {
    const canvas = this.makeCanvas(this.image);
    const texture = new CanvasTexture(canvas);

    // because our canvas is likely not a power of 2
    // in both dimensions set the filtering appropriately.
    texture.minFilter = LinearFilter;
    texture.wrapS = ClampToEdgeWrapping;
    texture.wrapT = ClampToEdgeWrapping;

    this.material = new SpriteMaterial({
      map: texture,
      transparent: true,
      depthTest: this.depthTest,
    });

    //如果以米为单位，这个值就填0.01
    const labelBaseScale = 0.1;
    this.rotateX(Math.PI / 2);
    //label.position.z = centerVector.z + headRadius + this.size * labelBaseScale;
    // label.position.z = centerVector.z + 1 + this.size * labelBaseScale;

    this.scale.x = canvas.width * labelBaseScale;
    this.scale.y = canvas.height * labelBaseScale;
    this.userData.originScaleX = this.scale.x;
    this.userData.originScaleY = this.scale.y;

    if (this.userData.modelScaleX)
      this.scale.x = this.scale.x * this.userData.modelScaleX;
    if (this.userData.modelScaleY)
      this.scale.y = this.scale.y * this.userData.modelScaleY;
  }

  /**
   * 修改POI的属性，执行此函数后无需执行make
   * @param cfg POI配置
   */
  public updateParams(cfg) {
    if (cfg.position) {
      cfg.position = cfg.position.toEPSGWeb();
      this.position.set(cfg.position.x, cfg.position.y, cfg.position.z);

      //删除cfg中的position属性
      delete cfg.position;
    }

    //把param中的属性写入到this中具有相同名称的属性中
    Object.assign(this, cfg);

    if (cfg.url) {
      this.image = new Image();
      let scope = this;
      let image = new Image();
      image.src = this.url;
      image.setAttribute('crossOrigin', 'anonymous');
      image.onload = function () {
        scope.image = image;
        scope.make();
      }
    }

    this.make();
  }

  public dispose() {

  }

}